package com.itxiuyixiu.volunteer.component;

import com.itxiuyixiu.entity.enums.*;
import com.itxiuyixiu.entity.mapper.*;
import com.itxiuyixiu.entity.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author 黄磊
 * @date 2020/5/6
 */
@Profile("data")
@Component
@Slf4j
public class TestDataComponent implements ApplicationRunner {
    @Resource
    private AdminWriterMapper adminWriterMapper;
    @Resource
    private TeacherWriterMapper teacherWriterMapper;
    @Resource
    private OrganizationWriterMapper organizationWriterMapper;
    @Resource
    private StudentWriterMapper studentWriterMapper;
    @Resource
    private UserWriterMapper userWriterMapper;
    @Resource
    private ProjectWriterMapper projectWriterMapper;
    @Resource
    private ActivityWriterMapper activityWriterMapper;
    @Resource
    private EnterListWriterMapper enterListWriterMapper;
    @Resource
    private TempStudentWriterMapper tempStudentWriterMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;

    private final String emailDomain = "@itxiuyixiu.com";
    private final String[] headImgList = {"头像1.png","头像2.png","头像3.png","头像4.png","头像5.png","头像6.png","头像7.png","头像8.png","头像9.png",};
    private final Random random = new Random();
    private final AtomicInteger studentInteger = new AtomicInteger();
    private final AtomicInteger emailInteger = new AtomicInteger();
    private final List<Student> students = Collections.synchronizedList(new ArrayList<>());

    private final ExecutorService executor = new ThreadPoolExecutor(0, 20,
            10L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(), new MyThreadFactory());

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void run(ApplicationArguments args) throws Exception {
        initUser("user0"+emailDomain, true);
        initUser("user1"+emailDomain, false);
        for (int i = 2; i < 20; i++) {
            initUser("user" + i + emailDomain, random.nextBoolean());
        }

        for (int i = 0; i < 5; i++) {
            initTeacher(i);
        }

        initOrganization(1, true);
        initOrganization(2, false);
        for (int i = 0; i < 20; i++) {
            initAdmin(i);
        }

        for (int i = 0; i < 20; i++) {
            initStudent();
        }
    }

    public void initUser(String username, boolean isStudent) {
        User user = new User();
        user.setUsername(username);
        user.setPassword(passwordEncoder.encode("123456"));
        user.setNickName(username);
        user.setUserEmail(username);
        user.setHeadImage("/"+headImgList[random.nextInt(headImgList.length)]);
        user.setAuthorities(AuthorityType.ROLE_USER);
        if (isStudent) {
            user.addAuthority(AuthorityType.ROLE_DHU_STUDENT);
        }
        executor.execute(() -> {
            userWriterMapper.saveUser(user);
            if (isStudent) {
                Student student = new Student();
                int number = studentInteger.getAndIncrement();
                student.setStudentName("学生" + number);
                student.setStudentId(String.format("%09d", number));
                student.setUserId(user.getUserId());
                student.setAcademy(DHUCollage.values()[random.nextInt(DHUCollage.values().length)]);
                studentWriterMapper.saveStudent(student);
                students.add(student);
                log.debug("创建学生" + student.getSId());
            }else if (random.nextBoolean()) {
                TempStudent tempStudent = new TempStudent();
                int number = studentInteger.getAndIncrement();
                tempStudent.setStudentName("学生" + number);
                tempStudent.setStudentId(String.format("%09d", number));
                tempStudent.setUserId(user.getUserId());
                tempStudent.setAcademy(DHUCollage.values()[random.nextInt(DHUCollage.values().length)]);
                tempStudentWriterMapper.saveTempStudent(tempStudent);
                log.debug("创建要认证的学生学生" + tempStudent.getTempStudentId());
            }
            log.debug("创建用户" + username);
        });
    }

    private void initStudent() {
        Student student = new Student();
        int number = studentInteger.getAndIncrement();
        student.setStudentName("学生" + number);
        student.setStudentId(String.format("%09d", number));
        student.setAcademy(DHUCollage.values()[random.nextInt(DHUCollage.values().length)]);
        studentWriterMapper.saveStudent(student);
        students.add(student);
        log.debug("创建学生" + student.getSId());
    }

    private void initTeacher(int index) {
        Admin admin = new Admin();
        admin.setUsername("admin_teacher" + index);
        admin.setPassword(passwordEncoder.encode("123456"));
        admin.setAdminEmail(emailInteger.getAndIncrement() + emailDomain);
        admin.setAuthorities(AuthorityType.ROLE_TEACHER_ADMIN);
        admin.addAuthority(AuthorityType.BASIC_ADMIN_AUTHORITY);
        admin.setAccountState(AccountState.PASSED);
        admin.setHeadImage("/"+headImgList[random.nextInt(headImgList.length)]);

        Teacher teacher = new Teacher();
        teacher.setTeacherName("老师" + index);
        executor.submit(() -> {
            try {
                adminWriterMapper.saveAdmin(admin);
                teacher.setAdminId(admin.getAdminId());
                teacherWriterMapper.saveTeacher(teacher);
            } catch (Exception e) {
                e.printStackTrace();
            }
            log.debug("创建老师"+index);
        });
    }

    private void initAdmin(int adminNumber) {
        Admin admin = new Admin();
        admin.setUsername("admin" + adminNumber);
        admin.setPassword(passwordEncoder.encode("123456"));
        admin.setAdminEmail(emailInteger.getAndIncrement() + emailDomain);
        admin.setHeadImage("/"+headImgList[random.nextInt(headImgList.length)]);
        if (random.nextBoolean()) {
            admin.setAuthorities(AuthorityType.ROLE_TEACHER_ADMIN);
        } else {
            admin.setAuthorities(AuthorityType.ROLE_VOLUNTEER_ORGANIZATION_ADMIN);
        }
        admin.addAuthority(AuthorityType.BASIC_ADMIN_AUTHORITY);
        if (random.nextBoolean()) {
            admin.setAccountState(AccountState.PASSED);
        } else {
            admin.setAccountState(AccountState.AUDITING);
        }
        executor.submit(() -> {
            adminWriterMapper.saveAdmin(admin);
            log.debug("创建管理员" + adminNumber);
        });
    }

    private void initOrganization(int organizationNumber, boolean isOfficial) {
        Admin admin = new Admin();
        admin.setUsername("admin_organization" + organizationNumber);
        admin.setPassword(passwordEncoder.encode("123456"));
        admin.setAdminEmail(emailInteger.getAndIncrement() + emailDomain);
        admin.setHeadImage("/"+headImgList[random.nextInt(headImgList.length)]);
        admin.setAuthorities(AuthorityType.ROLE_VOLUNTEER_ORGANIZATION_ADMIN);
        admin.addAuthority(AuthorityType.BASIC_ADMIN_AUTHORITY);
        if (isOfficial) {
            admin.addAuthority(AuthorityType.UPLOAD_STUDENT_MESSAGE);
        }
        admin.setAccountState(AccountState.PASSED);

        Organization organization = new Organization();
        organization.setOrgName("志愿者组织" + organizationNumber);
        organization.setAcademy(DHUCollage.CCEB);

        Project[] projects = new Project[5];
        for (int i = 0; i < projects.length; i++) {
            projects[i] = new Project();
            projects[i].setProjectName("志愿者组织" + organizationNumber + "—志愿者项目" + (i + 1));
        }

        Activity[] activities = new Activity[20];
        for (int i = 0; i < activities.length; i++) {
            activities[i] = new Activity();
            if (i < projects.length * 2) {
                activities[i].setActivityName("志愿者组织" + organizationNumber + "—志愿者项目" + ((i % projects.length) + 1) + "—志愿者活动" + (i + 1));
            } else {
                activities[i].setActivityName("志愿者组织" + organizationNumber + "—志愿者活动" + (i + 1));
            }
            if (random.nextBoolean()) {
                activities[i].setActivityDetail("志愿者组织" + organizationNumber + "—志愿者活动" + (i + 1) + "的活动详情");
            }
            activities[i].setStartTime(LocalDateTime.now().plusDays(i));
            activities[i].setEndTime(LocalDateTime.now().plusDays(i * 2));
            activities[i].setOutTime(LocalDateTime.now().minusDays(i));
            activities[i].setActivityAddress("活动地点");
            activities[i].setMaxNumber(random.nextInt(30) + 1);
            activities[i].setAttention("志愿者组织" + organizationNumber + "—志愿者活动" + (i + 1) + "注意");
            activities[i].setActivityType(ActivityType.values()[random.nextInt(ActivityType.values().length)]);
            activities[i].setServeHours(Float.parseFloat(Integer.toString(random.nextInt(7)))+1);
            if (random.nextInt(10) > 7) {
                activities[i].setAcademyLimited(true);
                activities[i].setAcademyLimitedList(DHUCollage.values()[random.nextInt(10)].toString());
            } else {
                activities[i].setAcademyLimited(false);
            }
            if (random.nextBoolean()) {
                activities[i].setActivityState(ActivityState.AUDITING);
            } else {
                activities[i].setActivityState(ActivityState.PASSED);
            }
        }

        executor.execute(() -> {
            adminWriterMapper.saveAdmin(admin);
            organization.setAdminId(admin.getAdminId());
            organizationWriterMapper.saveOrganization(organization);
            for (Project project : projects) {
                project.setAdminId(admin.getAdminId());
                project.setOrganizationId(organization.getOrganizationId());
                projectWriterMapper.saveProject(project);
                log.debug("创建项目" + project.getProjectId());
            }

            for (int i = 0; i < activities.length; i++) {
                int j = i;
                activities[i].setAdminId(admin.getAdminId());
                activities[i].setOrganizationId(organization.getOrganizationId());
                if (random.nextBoolean()) {
                    activities[i].setProjectId(projects[(i % projects.length)].getProjectId());
                }
                executor.execute(() -> {
                    activityWriterMapper.saveActivity(activities[j]);
                    if (activities[j].getActivityState().compare(ActivityState.PASSED)<0 || activities[j].getActivityState().equals(ActivityState.CANCELED)) {
                        return;
                    }
                    for (int m = 0; m < students.size() && m < activities[j].getMaxNumber(); m++) {
                        if (random.nextBoolean()) {
                            EnterList enterList = new EnterList();
                            enterList.setEnterHours(activities[j].getServeHours());
                            enterList.setSId(students.get(m).getSId());
                            enterList.setActivityId(activities[j].getActivityId());
                            enterListWriterMapper.enterActivity(students.get(m).getSId(),activities[j].getActivityId(), activities[j].getServeHours());
                            log.debug("活动参与" + enterList.getEnterId());
                        }
                    }
                    if (activities[j].getActivityState().equals(ActivityState.FINISHED)) {
                        activityWriterMapper.finishActivity(activities[j].getActivityId());
                    }
                    log.debug("创建活动" + activities[j].getActivityId());
                });
            }
        });
    }

    public static class MyThreadFactory implements ThreadFactory {

        private final AtomicInteger number = new AtomicInteger(0);

        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, "生成数据线程" + number.getAndIncrement());
        }
    }
}
